package com.hexacta.hrs.service.staffing.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.functors.AllPredicate;
import org.apache.tools.ant.util.DateUtils;
import org.vectrics.common.util.DateUtil;
import org.vectrics.employee.Employee;

import com.hexacta.hrs.domain.staffing.Project;
import com.hexacta.hrs.domain.staffing.Requirement;
import com.hexacta.hrs.domain.staffing.assignment.AssignmentType;
import com.hexacta.hrs.domain.staffing.assignment.EmployeeAssignment;
import com.hexacta.hrs.repositories.ProjectRepository;
import com.hexacta.hrs.service.staffing.ProjectService;
import com.hexacta.hrs.services.staffing.impl.predicates.DateRequirementPredicate;
import com.hexacta.hrs.services.staffing.impl.predicates.RolesRequirementPredicate;

/**
 * Implementation of ProjectService.
 * 
 * @author nscuri
 *
 */
public class ProjectServiceImpl implements ProjectService {

	private ProjectRepository projectRepository;

	@Override
	public List<Project> findAll() {
		return projectRepository.findAll();
	}

	public void setProjectRepository(ProjectRepository projectRepository) {
		this.projectRepository = projectRepository;
	}

	public ProjectRepository getProjectRepository() {
		return projectRepository;
	}

	@Override
	public Project createNew() {
		return new Project();
	}

	@Override
	public void delete(Project recordObject) {
		this.getProjectRepository().delete(recordObject);
	}

	@Override
	public void save(Project recordObject) {
		this.getProjectRepository().save(recordObject);
	}

	@Override
	public Collection<Project> searchByCriteria(Project criteria) {
		return this.getProjectRepository().matching(criteria);
	}

	@Override
	public Project searchById(long id) {
		return this.getProjectRepository().forId(id);
	}

	@Override
	public List<Requirement> findAllRequirements() {
		List<Project> projects = this.findAll();
		List<Requirement> requirements = new ArrayList<Requirement>();
		for (Project project : projects) {
			requirements.addAll(project.getRequirements());
		}
		return requirements;
	}

	@Override
	public Set<Requirement> findRequirements(long projectId,
			Date selectedFromDate, Date selectedToDate,
			Collection<String> selectedRoles) {
		Project project = this.searchById(projectId);
		Set<Requirement> requirements = project.getRequirements();

		ArrayList<Predicate> predList = new ArrayList<Predicate>();
		if (selectedFromDate != null || selectedToDate != null) {
			predList.add(new DateRequirementPredicate(selectedFromDate,
					selectedToDate));
		}
		if (!CollectionUtils.isEmpty(selectedRoles)) {
			predList.add(new RolesRequirementPredicate(selectedRoles));
		}

		Predicate[] pred = new Predicate[] {};

		if (!predList.isEmpty()) {
			pred = predList.toArray(pred);
			AllPredicate predicate = new AllPredicate(pred);
			CollectionUtils.filter(requirements, predicate);
		}

		return requirements;
	}
	
	@Override
	public List<Employee> findRequirementResults(Requirement requirement) {
		return projectRepository.findRequirementResults(requirement);
	}

	@SuppressWarnings("deprecation")
	@Override
	public List<Project> searchProjects(Map<String, Object> filters) {
		
		Date dateFrom = null;
		Date dateTo = null;
		
		if ( filters.get("dateFrom") != null && !((String) filters.get("dateFrom")).isEmpty()) {
			try {
				dateFrom = DateUtils.parseIso8601Date((String) filters.get("dateFrom"));
			} catch (ParseException e) {
				dateFrom = (Date) filters.get("dateFrom");
			} catch (ClassCastException e) {
				dateFrom = (Date) filters.get("dateFrom");
			}
		} else {
			Calendar actualDate = Calendar.getInstance();
			actualDate.set(Calendar.MONTH, Calendar.JANUARY);
			actualDate.set(Calendar.DAY_OF_MONTH, 1);
			dateFrom = (actualDate.getTime());
		}
		
		if ( filters.get("dateTo") != null && !((String) filters.get("dateTo")).isEmpty()) {
			try {
				dateTo = DateUtils.parseIso8601Date((String) filters.get("dateTo"));
			} catch (ParseException e) {
				dateTo = (Date) filters.get("dateTo");
			} catch (ClassCastException e) {
				dateTo = (Date) filters.get("dateTo");
			}
		} else {
			Calendar actual = Calendar.getInstance();
			actual.set(Calendar.YEAR,dateFrom.getYear() + 1900);
			dateTo = (actual.getTime());
			dateTo.setMonth(11);
			dateTo.setDate(31);
		}
		
		//TODO: COMMENT FOR TEST.
		Boolean showInternal = (Boolean) filters.get("showInternal");
		Boolean showAssignedToClient = (Boolean) filters.get("showAssignedToClient");
		Boolean showAddOnAvailable = (Boolean) filters.get("showAddOnAvailable");
		Boolean showAddOnNotAvailable = (Boolean) filters.get("showAddOnNotAvailable");
		
		List<Project> initialProjects = projectRepository.search(filters);
		List<Project> finalProjects = new ArrayList<Project>();
		
		for(Project project : initialProjects) {
			
			Project auxiliarProject = new Project();
			auxiliarProject.setName(project.getName());
			auxiliarProject.setClient(project.getClient());
			
			if (showInternal != null && showInternal == true && !showInternal.equals(project.isInternalProject())) {
				continue;
			}
			for(EmployeeAssignment assignment : project.getAssignments()) {
				boolean save = true;
				if (dateFrom != null &&
							DateUtil.mayorIgual(dateFrom, assignment.getStartDate().getTime())) {
					save = false;
				}
				if (dateTo != null &&
						DateUtil.menorIgual(dateTo, assignment.getEndDate().getTime())) {
					save = false;
				}
				if (showAssignedToClient != null && showAssignedToClient == true && !showAssignedToClient.equals(
						assignment.getAssignmentType().toString().equals(AssignmentType.Assigned.toString()))) {
					save = false;
				}
				if (showAddOnAvailable != null && showAddOnAvailable == true && !showAddOnAvailable.equals(
						assignment.getAssignmentType().toString().equals(AssignmentType.AddOnAvailable.toString()))) {
					save = false;
				}
				if (showAddOnNotAvailable != null && showAddOnNotAvailable == true && !showAddOnNotAvailable.equals(
						assignment.getAssignmentType().toString().equals(AssignmentType.AddOnNotAvailable.toString()))) {
					save = false;
				}
				if(save) {
					auxiliarProject.addAssignment(assignment);
				}
			}
			if (auxiliarProject.getAssignments().size() >= 1) {
				finalProjects.add(auxiliarProject);
			}
		}

        return finalProjects;
	}

	/* (non-Javadoc)
	 * @see com.hexacta.hrs.service.staffing.ProjectService#searchByName(java.lang.String)
	 */
	@Override
	public Project searchByName(String name) {
		return this.projectRepository.searchByName(name);
	}
}
